﻿using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.AgentOrigins;
using TaleWorlds.Core;
using TaleWorlds.Engine;
using TaleWorlds.InputSystem;
using TaleWorlds.Library;
using TaleWorlds.MountAndBlade;

namespace MarriageFertility.Helpers;

public static class MissionHelper
{  
    public static Dictionary<string, Color> ColorDict = new();
    
    public static Dictionary<Agent, string> AgentNameDict = new();
    private static Random _random = new Random();
    
    public static Color GetRandomColor()
    {

        float r = (float)(_random.NextDouble() * 0.5 + 0.5);
        float g = (float)(_random.NextDouble() * 0.5 + 0.5);
        float b = (float)(_random.NextDouble() * 0.5 + 0.5);
        return new Color(r, g, b);
    }
    
    public static Color GetNameFontColor(this string name)
    {
            if (ColorDict.ContainsKey(name)) return ColorDict[name];
            else
            {
                Color color = GetRandomColor();
                ColorDict.Add(name,color);
                return color;
            }
    }
    public static Agent SpawnAgent(CharacterObject character, MatrixFrame spawnFrame, bool isPlayer, bool isFriend,
        bool spawnBothSidesWithHorses)
    {
        var team = isPlayer ? Mission.Current.PlayerTeam : Mission.Current.PlayerEnemyTeam;
        var agentBuildData = new AgentBuildData(character)
            .Team(team)
            .InitialPosition(spawnFrame.origin)
            .InitialDirection(spawnFrame.rotation.f.AsVec2.Normalized())
            .NoHorses(!spawnBothSidesWithHorses)
            .Equipment(character.FirstBattleEquipment)
            .TroopOrigin(GetAgentOrigin(isFriend, character))
            .ClothingColor1(character.Culture.Color)
            .ClothingColor2(character.Culture.Color2);

        Agent agent = Mission.Current.SpawnAgent(agentBuildData);
        agent.FadeIn();

        if (isPlayer)
        {
            agent.Controller = Agent.ControllerType.Player;
            Mission.Current.MainAgent = agent;
        }
        else
        {
            if (agent.IsAIControlled)
            {
                agent.SetWatchState(Agent.WatchState.Alarmed);
            }
        }

        agent.WieldInitialWeapons();
        return agent;
    }

    public static (MatrixFrame, MatrixFrame) GetBattleSpawnFrames()
    {
        var spawnPoint = (Mission.Current.Scene.FindEntityWithTag("attacker_infantry") ??
                          Mission.Current.Scene.FindEntityWithName("sp_attacker_infantry")).GlobalPosition.AsVec2;
        return CalculateSpawnFrames(spawnPoint, 10f);
    }

    public static (MatrixFrame, MatrixFrame) GetArenaSpawnFrames()
    {
        var spawnPoints = Mission.Current.Scene.FindEntitiesWithTag("sp_arena")
            .Select(e => e.GetGlobalFrame())
            .ToList();

        spawnPoints.ForEach(sp => sp.rotation.OrthonormalizeAccordingToForwardAndKeepUpAsZAxis());

        var playerSpawnFrame = spawnPoints.GetRandomElement();
        spawnPoints.Remove(playerSpawnFrame);
        var opponentSpawnFrame = spawnPoints.GetRandomElement();

        return (playerSpawnFrame, opponentSpawnFrame);
    }

    private static (MatrixFrame playerSpawnFrame, MatrixFrame opponentSpawnFrame) CalculateSpawnFrames(Vec2 centerPoint,
        float distance)
    {
        float height = 0.00f;
        Mission.Current.Scene.GetHeightAtPoint(new Vec2(centerPoint.X, centerPoint.Y + distance),
            BodyFlags.CommonCollisionExcludeFlagsForCombat, ref height);
        var forwardPos = new Vec3(centerPoint.X, centerPoint.Y + distance, height);
        var forwardFrame = new MatrixFrame(Mat3.Identity, forwardPos);

        Mission.Current.Scene.GetHeightAtPoint(new Vec2(centerPoint.X, centerPoint.Y - distance),
            BodyFlags.CommonCollisionExcludeFlagsForCombat, ref height);
        var backwardPos = new Vec3(centerPoint.X, centerPoint.Y - distance, height);
        var backwardFrame = new MatrixFrame(Mat3.Identity, backwardPos);
        return (backwardFrame, forwardFrame);
    }

    private static IAgentOriginBase GetAgentOrigin(bool isFriendDuel, CharacterObject character)
    {
        return isFriendDuel
            ? new SimpleAgentOrigin(character, character.Level)
            : new PartyAgentOrigin(character.HeroObject.PartyBelongedTo?.Party, character, character.Level);
    }
    
    public static List<GameEntity> GetSpawnPoints(int agentNumber)
    {
        List<GameEntity> list = new List<GameEntity>();
        for (int i = 0; i < agentNumber; i++)
        {
            GameEntity gameEntity = Mission.Current.Scene.FindEntityWithTag("sp_arena_" + (i + 1));
            if (gameEntity != null)
            {
                list.Add(gameEntity);
            }
        }
        if (list.Count < agentNumber)
        {
            list = Mission.Current.Scene.FindEntitiesWithTag("sp_arena").ToList<GameEntity>();
        }
        return list;
    }
    
    public static Hero GetHero(this Agent agent)
    {
        if (agent == null || agent.Character == null || !agent.IsHero) return null;
        return (agent.Character as CharacterObject)?.HeroObject;
    }

    
    public static void SetLeaveKey()
    {
        var leaveKeyText = Game.Current.GameTextManager.GetHotKeyGameTextFromKeyID(
            HotKeyManager.GetAllCategories()
                .FirstOrDefault(r => r.GameKeyCategoryId == "Generic")?
                .RegisteredGameKeys[4].KeyboardKey.ToString());
				
        GameTexts.SetVariable("leave_key", leaveKeyText);
    }
}